From 4a0d7d86f063b399a7549d20f24cc7f4ae059b0e Mon Sep 17 00:00:00 2001
From: Pierre Joye <pierre.php@gmail.com>
Date: Wed, 1 Sep 2021 14:05:56 +0700
Subject: [PATCH] Fix #320, should not convert the source to palette

---
 src/gd_interpolation.c                  | 34 +++++++++++++++----------
 tests/gdimagecopyrotated/CMakeLists.txt |  3 +++
 tests/gdimagecopyrotated/bug00320.c     | 22 ++++++++++++++++
 3 files changed, 46 insertions(+), 13 deletions(-)
 create mode 100644 tests/gdimagecopyrotated/bug00320.c

diff --git a/src/gd_interpolation.c b/src/gd_interpolation.c
index 9f743fe0d..6a4d6c9a8 100644
--- a/src/gd_interpolation.c
+++ b/src/gd_interpolation.c
@@ -1829,19 +1829,19 @@ BGD_DECLARE(gdImagePtr) gdImageRotateInterpolated(const gdImagePtr src, const fl
 	   case later. Keep the two decimal precisions so smaller rotation steps can be done, useful for
 	   slow animations, f.e. */
 	const int angle_rounded = fmod((int) floorf(angle * 100), 360 * 100);
-
+	gdImagePtr src_tc = src;
+	int src_cloned = 0;
 	if (src == NULL || bgcolor < 0) {
 		return NULL;
 	}
 
-	/* impact perf a bit, but not that much. Implementation for palette
-	   images can be done at a later point.
-	*/
-	if (src->trueColor == 0) {
+	if (!gdImageTrueColor(src)) {
 		if (bgcolor < gdMaxColors) {
 			bgcolor =  gdTrueColorAlpha(src->red[bgcolor], src->green[bgcolor], src->blue[bgcolor], src->alpha[bgcolor]);
 		}
-		gdImagePaletteToTrueColor(src);
+		src_tc = gdImageClone(src);
+		gdImagePaletteToTrueColor(src_tc);
+		src_cloned = 1;
 	}
 
 	/* 0 && 90 degrees multiple rotation, 0 rotation simply clones the return image and convert it
@@ -1853,38 +1853,46 @@ BGD_DECLARE(gdImagePtr) gdImageRotateInterpolated(const gdImagePtr src, const fl
 			if (dst == NULL) {
 				return NULL;
 			}
-			if (dst->trueColor == 0) {
-				gdImagePaletteToTrueColor(dst);
-			}
+			if (src_cloned) gdImageDestroy(src_tc);
 			return dst;
 		}
 
 		case -27000:
 		case   9000:
+			if (src_cloned) gdImageDestroy(src_tc);
 			return gdImageRotate90(src, 0);
 
 		case -18000:
 		case  18000:
+			if (src_cloned) gdImageDestroy(src);
 			return gdImageRotate180(src, 0);
 
 		case  -9000:
 		case  27000:
+			if (src_cloned) gdImageDestroy(src_tc);
 			return gdImageRotate270(src, 0);
 	}
 
 	if (src->interpolation_id < 1 || src->interpolation_id > GD_METHOD_COUNT) {
+		if (src_cloned) gdImageDestroy(src_tc);
 		return NULL;
 	}
 
 	switch (src->interpolation_id) {
-		case GD_NEAREST_NEIGHBOUR:
-			return gdImageRotateNearestNeighbour(src, angle, bgcolor);
+		case GD_NEAREST_NEIGHBOUR: {
+			gdImagePtr res = gdImageRotateNearestNeighbour(src, angle, bgcolor);
+			if (src_cloned) gdImageDestroy(src_tc);
+			return res;
 			break;
+		}
 
 		case GD_BILINEAR_FIXED:
 		case GD_BICUBIC_FIXED:
-		default:
-			return gdImageRotateGeneric(src, angle, bgcolor);
+		default: {
+			gdImagePtr res = gdImageRotateGeneric(src, angle, bgcolor);
+			if (src_cloned) gdImageDestroy(src_tc);
+			return res;
+		}
 	}
 	return NULL;
 }
diff --git a/tests/gdimagecopyrotated/CMakeLists.txt b/tests/gdimagecopyrotated/CMakeLists.txt
index 7f1a67867..7d4f0015d 100644
--- a/tests/gdimagecopyrotated/CMakeLists.txt
+++ b/tests/gdimagecopyrotated/CMakeLists.txt
@@ -1,3 +1,6 @@
+LIST(APPEND TESTS_FILES
+	bug00320
+)
 IF(PNG_FOUND)
 LIST(APPEND TESTS_FILES
 	bug00020
diff --git a/tests/gdimagecopyrotated/bug00320.c b/tests/gdimagecopyrotated/bug00320.c
new file mode 100644
index 000000000..72ff363c6
--- /dev/null
+++ b/tests/gdimagecopyrotated/bug00320.c
@@ -0,0 +1,22 @@
+#include "gd.h"
+#include "gdtest.h"
+
+#define width 20
+
+int main()
+{
+    gdImagePtr src, dst;
+    int black;
+
+    src = gdImageCreate(10, 10);
+    black = gdImageColorAllocate(src, 0, 0, 0);
+
+    gdTestAssert(gdImageTrueColor(src) == 0);
+    dst = gdImageRotateInterpolated(src, 30.0, black);
+    gdTestAssert(dst != NULL);
+    gdTestAssert(gdImageTrueColor(src) == 0);
+
+	gdImageDestroy(src);
+	gdImageDestroy(dst);
+	return gdNumFailures();
+}
